import os
import Treenode

from pypbc import *

path = os.path.dirname(__file__)

def getY(index,coef,pairing):
    print('gety')
    res = coef[0]
    index = Element(pairing,Zr,value=index)
    print('index',index)
    for i in range(len(coef)):
        exp = Element(pairing,Zr,value=i)
        res = res.__add__(coef[i].__mul__(index.__pow__(exp)))
    return res

def setup():
    U = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

    q1 = get_random_prime(60)
    q2 = get_random_prime(60)

    params = Parameters(n=q1 * q2)
    paramsfile = open(path + '/pairingparams.txt', 'w')
    paramsfile.write(str(params))

    # paramsfile = open('pairingparams.txt','r')
    # params_str = paramsfile.read()
    # params = Parameters(params_str)

    pairing = Pairing(params)
    g = Element.random(pairing, G1)

    MK = {}
    PK = {}

    y = Element.random(pairing, Zr)
    Y = (pairing.apply(g, g)) ** y  # Y=e(g,g)**y #pbc.Elemnt

    MK['y'] = y.__int__()
    PK['Y'] = Y.__str__()
    PK['g'] = g.__str__()

    # gs = Element(pairing,G1,value=g.__str__())
    # ys = Element(pairing,Zr,value=y.__int__())
    # Ys = Element(pairing,GT,value=Y.__str__())
    # print(Ys)
    # print(type(Ys))

    for i in range(1, len(U) + 1):
        t = Element.random(pairing, Zr)
        T = Element(pairing, G1, value=g ** t)  # Ti = g**c
        MK['t' + str(i)] = t.__int__()
        PK['T' + str(i)] = T.__str__()

    # publish PK on blockchian
    pkfile = open(path + '/PK.txt', 'w')
    pkstr = str(PK)
    pkfile.write(pkstr)
    pkfile.close()

    print(MK)
    print(PK)
    # store MK in localstorage
    mkfile = open(path + '/MK.txt', 'w')
    mkstr = str(MK)
    mkfile.write(mkstr)
    mkfile.close()

    # read MK
    # f = open('MK.txt','r')
    # mks = f.read()
    # mk = eval(mks)
    # f.seek(0)


def Enc(M, gama, PK, pairing):
    # 将M映射到G2
    print('start enc')
    # M = Element.from_hash(pairing, GT, M)  # dont need manual hash,automic get data hash
    s = Element.random(pairing, Zr)

    y = eval(open(os.path.dirname(__file__) + '/../sys/MK.txt').read())['y']
    g = eval(open(os.path.dirname(__file__) + '/../sys/PK.txt').read())['g']
    y = Element(pairing, Zr, value=int(y, 16))

    g = Element(pairing, G1, value=g)
    # pkfile = open('./sys/PK.txt','r')
    # PK = eval(pkfile.read())
    # gs= PK['g']
    # g=Element(pairing,G1,value=gs)

    Y = (pairing.apply(g, g)) ** y
    print("!Ys:",Y**s)
    E_b = M * (Y ** s)
    E_s = []
    for gi in gama:
        ti = PK['T' + str(gi)]
        Ti = Element(pairing, G1, value=ti)
        E_s.append([Element(pairing, G1, value=Ti ** s), gi])
        # E_s.append([Ti**s,gi])
    print('enc end')
    return [gama, E_b, E_s]


def DEC(E, D, ACT, pairing):
    print('dec start')
    for di in D:
        di[0] = Element(pairing, G1, value=di[0])

    def findindex(D, attr):
        for index in range(len(D)):
            if (D[index][1] == attr):
                return index
        return -1

    def lagrange(i, S, x, pairing):
        print('calc delta for', i)
        res = Element.one(pairing, Zr)
        i = Element(pairing, Zr, value=i)
        x = Element(pairing, Zr, value=x)
        for j in S:
            j = Element(pairing, Zr, value=j[1])  # 取得相对索引
            if (i != j):
                nume = x.__add__(Element(pairing, Zr, value=j).__neg__())
                deno = i.__add__(Element(pairing, Zr, value=j).__neg__())
                res = res.__mul__(nume.__mul__(deno.__pow__(-1)))

        return res

    def findLeaf(node):
        if (node.type == 'attr'):
            index1 = findindex(D, node.value)
            index2 = findindex(E[2], node.value)
            if (index1 != -1 and index2 != -1):
                return pairing.apply(D[index1][0], E[2][index2][0])  # if i in gama retuen e(dx,ei)
            else:
                return -1  # G2 dedibianjie (zuixiaozhi cankao gelun
        else:
            Sx = []
            index = 0
            for child in node.child:
                if (len(Sx) != child.value):
                    fz = findLeaf(child)
                    index += 1
                    if (type(fz) != int):
                        Sx.append([fz, index])
                else:
                    break
            # delta = lagrang vlaue where x =
            # satisfied kx,cacl
            # if(node.isRoot):
            #     return Sx[0]
            if (not (len(Sx) >= node.value)):
                print('fail node')
                return -1
            else:
                fx = Element.one(pairing, GT)
                for f in Sx:
                    delta = lagrange(f[1], Sx, 0, pairing)
                    fx = fx.__mul__(f[0].__pow__(delta))
                return fx

    Ys = findLeaf(ACT)
    return Ys


def GenACT():
    Node = Treenode.Node

    ACT = Node('k', 1,0)
    ACT.Root()
    node1 = Node('attr', 1,1)
    node2 = Node('k', 2,2)
    node3 = Node('attr', 2,2)
    node4 = Node('attr', 4,4)
    ACT.appendChild(node1)
    node2.appendChild(node3)
    node2.appendChild(node4)
    ACT.appendChild(node2)

    return ACT


def randomP(d, s, pairing):
    coef = []
    coef.append(s)
    for i in range(1, d):
        coef.append(Element.random(pairing, Zr))

    return coef


def KG(ACT):
    D = []
    mkfile = open('./MK.txt')
    MK = eval(mkfile.read())
    mkfile.close()
    y = MK['y']
    y = Element(pairing, Zr, value=y)
    g = eval(open(os.path.dirname(__file__) + '/PK.txt').read())['g']
    g = Element(pairing, G1, value=g)

    def nodeShare(node,b,pairing):
        if(node.type != 'attr'):
            node.poly = randomP(node.value,b,pairing)
            #node.poly.reverse()
            for j in range(len(node.child)):
                nodeShare(node.child[j].index,getY(j),pairing)
        else:
            node.poly.append(b)
            qx = node.poly[len(node.poly) - 1]
            q = Element(pairing, Zr, value=qx)
            t = MK['t' + str(node.value)]
            t = Element(pairing, Zr, value=t)
            # print('q',q)
            # print('t',t)
            Di = g.__pow__(q.__mul__(t.__pow__(-1)))
            print(Di)
            D.append([Di,node.value])

    def KeyGen(ACT):
        mkfile = open('./MK.txt')
        MK = eval(mkfile.read())
        mkfile.close()
        y = MK['y']
        y = Element(pairing, Zr, value=y)
        g = eval(open(os.path.dirname(__file__) + '/PK.txt').read())['g']
        g = Element(pairing, G1, value=g)

        d = ACT.value
        # ACT.poly.append(y)
        # for i in range(0, d):
        #     ACT.poly.append(random.randint(1, 10))
        ACT.poly = randomP(d, y, pairing)
        ##ACT.poly.reverse()
        for index in range(len(ACT.child)):
            b = ACT.getY(index)
            GenPoly(ACT.child[index], b, MK, g)

    def GenPoly(child, b, MK, g):
        d = child.value
        # child.poly.append(b)
        # for i in range(0, d):
        #     child.poly.append(random.randint(1, 10))
        child.poly = randomP(d, b, pairing)
        child.poly.reverse()

        if (child.type == 'attr'):
            qx = child.poly[len(child.poly) - 1]
            q = Element(pairing, Zr, value=qx)
            t = MK['t' + str(child.value)]
            t = Element(pairing, Zr, value=t)
            # print('q',q)
            # print('t',t)
            Di = g.__pow__(q.__mul__(t.__pow__(-1)))
            print(Di)
            D.append([Di, child.value])
        lens = len(child.child)
        if lens != 0:
            for index in range(len(child.child)):
                b = child.getY(index)
                GenPoly(child.child[index], b, MK, g)

    #KeyGen(ACT)
    nodeShare(ACT,y,pairing)
    return D
setup()

ACT = GenACT()

ppfile = open('./pairingparams.txt', 'r')
params = Parameters(ppfile.read())
pairing = Pairing(params)
PK = eval(open(os.path.dirname(__file__) + '/PK.txt').read())
Y = PK['Y']

M = Element.from_hash(pairing, GT, '123')

E = Enc(M, [2, 4], PK, pairing)
print('E', E)
D = KG(ACT)
print('D', D)
Ys = DEC(E, D, ACT, pairing)
print('Ys',Ys)

eM = E[1].__mul__(Ys.__pow__(-1))
print('M',M)
print('eM', eM)
